let animation; // 动画对象

class Animation {
  constructor(config) {
    this.config = config;
    this.cpointer = 0; // 转盘编码器
    this.vpointer = 0; // 虚拟指针
    this.lastPointerTime = performance.now(); // 指针最后一次移动的时间
    this.screen = new Map(); // 屏幕信息
    this.elements = new Map(); // 存储需要执行动画的元素
    this.visiableElements = new Map(); // 存储元素状态
    this.elementTimestamps = new Map(); // 存储元素创建时间戳
    this.running = false; // 动画运行状态
    this.speed = config.speed || 78; // 每秒移动的像素数
    this.animationFrameId = null; // requestAnimationFrame的ID
    if (config.direction === 'left-right') {
      this.StartPostionElement = window.innerWidth;
      this.positionReference = 'right';
      this.presetstep = config.presetStep;
    } 
    if (config.direction === 'right-left') {
      this.StartPostionElement = config.MonitorWidth;
      this.positionReference = 'left';
      this.presetstep = -config.presetStep;
    }
    // this.presetstep = -config.presetStep;

    const element = document.createElement('div');// 创建一个模板元素，后续的元素都从这个模板克隆
    element.id = 'template';
    element.style.fontFamily = config.template.fontFamily || 'Arial, sans-serif';
    element.style.fontSize = config.template.fontSize || '20px';
    element.style.color = config.template.color || 'green';
    element.style.width = config.template.width || '300px';
    element.style.position = 'absolute';
    element.style[this.positionReference] = `${this.StartPostionElement}px`;
    this.templateElement = element;

    let curBottom = window.innerHeight - config.MonitorHeight;  // 用于累加计算 bottom
    if (curBottom < 0) {
      curBottom = 0;
    }
    config.screen.forEach((scr, index) => {
      const rows = Math.ceil(scr.len_pix / config.MonitorWidth);
      const bottomValue = [];
      for (let i=0; i<rows; i++) {
        bottomValue.push(curBottom);
        curBottom -= config.MonitorHeight;  // 累加 bottom 值，供下一个屏幕使用'
      }
      this.screen.set(scr.start,bottomValue);
    });
    this.timeoutPointerInterval = 200; // 定时器持续时间（毫秒）
    this.timeoutPointerIntervalID = null; // 定时器ID
    this.control();
    // 创建 Intersection Observer
    this.observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        const id = entry.target.id;
        if (!entry.isIntersecting) {
          this.removeElement(id);
        }
      });
    }, {
      root: null, // 使用视口作为根
      threshold: 0 // 当元素完全不可见时触发
    });
}

// 在添加元素时启用观察
creatElement(screen_baggageInfolist) {
    const timestamp = performance.now();
    for (const ScreenStartPos in screen_baggageInfolist) {
      const baggageInfolist = screen_baggageInfolist[ScreenStartPos];
      
      const bottomValue = this.screen.get(Number(ScreenStartPos));
      for (let i=0; i<baggageInfolist.length; i++) {
        const baggageInfo = baggageInfolist[i];
        // 克隆模板元素
        const layer = baggageInfo.layer;
        let innerHTML;
        if (baggageInfo.flight ) {
          innerHTML = baggageInfo.flight +'<BR>'+ baggageInfo.dest +'<BR>'+ baggageInfo.lpc.substr(-4);
        } else {
          innerHTML = baggageInfo.key;
        }
        let color;
        if ((baggageInfo.ScheduledDateTime - timestamp)/60000 <= baggageInfo.minBeforeSDT) {
          color = 'red';
        } else {
          color ='green';
        }

        const idlabeltime = baggageInfo.lpc+'-'+humanizeTime();
        let id = idlabeltime;
        for (let i=0; i<bottomValue.length; i++) {
          const element = this.templateElement.cloneNode(true);
          element.id = id
          element.innerHTML = innerHTML;
          element.style.bottom = `${bottomValue[i] + this.config.layerHeight*layer}px`;
          element.style.color = color;
          this.elements.set(id, element);
          id += '-next';
        }

        this.visiableElements.set(idlabeltime, { position: this.StartPostionElement, distance: 0 });

        const element = this.elements.get(idlabeltime);
        if (baggageInfo.screenOffset) {
          element.style[this.positionReference] = `${this.StartPostionElement - baggageInfo.screenOffset}px`;
          this.visiableElements.set(idlabeltime, { position: this.StartPostionElement - baggageInfo.screenOffset, distance: baggageInfo.screenOffset});
        }
        document.body.appendChild(element);
        console.log(idlabeltime,'created');
      };
       
    };
  }
  
  removeElement(label) {
    const element = this.elements.get(label);
    if (element) {
      this.observer.unobserve(element);
      element.remove(); // 从DOM中移除元素
      this.elements.delete(label); // 从animation.elements中删除
    }
    this.visiableElements.delete(label);
    console.log(label,'removed');
  }
  newpointer() {
    this.lastPointerTime = performance.now();

  }
  control = () => {
    const timestamp = performance.now();
    const frameInterval = timestamp - (this._lastFrameTime || timestamp);
    this._lastFrameTime = timestamp;
    if ((timestamp - this.lastPointerTime) < this.timeoutPointerInterval) {
      if (!this.running) {
        console.log(`${humanizeTime()}:Animation started, pointer interval=${timestamp - this.lastPointerTime}}`);
      }
      this.running = true;
      this.step = this.presetstep;
    } else {
      if (this.running) {
        console.log(`${humanizeTime()}:Animation stopped, pointer interval=${timestamp - this.lastPointerTime}}`);
      }
      this.running = false;
      this.step = 0;
    }
    for (const [label,elementState] of this.visiableElements) {
      const element = this.elements.get(label);
      if (elementState) {
        elementState.position += this.step/(1000/60)*frameInterval;
        elementState.distance += this.step/(1000/60)*frameInterval;
        element.style.transform = `translateX(${elementState.distance}px)`;
        // console.log(elementState.distance);
        if (Math.abs(elementState.distance) > this.config.MonitorWidth ) {
          const nextlabel = label + '-next';
          if (!this.visiableElements.has(nextlabel)) {
            if (this.elements.has(nextlabel)) {
              this.visiableElements.set(nextlabel, { position: this.StartPostionElement, distance: 0 });
              document.body.appendChild(this.elements.get(nextlabel));
            }
          }
          this.observer.observe(element); 
        }
      }
    };

    if (frameInterval > 19) {
      const procestime = performance.now() - timestamp
      console.log(`${humanizeTime()}:Frame interval: ${frameInterval.toFixed(2)}ms,proces time=${procestime.toFixed(2)}ms,elements=${this.visiableElements.size}`);
    }

    this.animationFrameId = requestAnimationFrame(this.control);
  }
  presureTestAnimation(interval,times) {
    let count = 0;
    const timer = setInterval(() => {
      const screen_baggageInfolist = {};
      this.screen.forEach((bottomValue, ScreenStartPos) => {
        screen_baggageInfolist[ScreenStartPos] = [{flight: `SCR${ScreenStartPos}`, dest: 'LAYER0', layer: 0, lpc: `S${ScreenStartPos}L0C${count}`},
                            {flight: `SCR${ScreenStartPos}`, dest: 'LAYER1', layer: 1, lpc: `S${ScreenStartPos}L1C${count}`}];
      }); 
      this.creatElement(screen_baggageInfolist);
      count++;
      if (count >= times) {
        clearInterval(timer);
      }
    }, interval);
  }
}

if ("electron" in window) {
  document.addEventListener("DOMContentLoaded", () => {
    // 禁用屏幕缩放
    // 使用物理像素，不设置缩放限制
    if (window.electron.webFrame) {
      window.electron.webFrame.setZoomLevel(0);
    }
    
    window.electron.receiveMessage("config", (data) => {
        const config = JSON.parse(data);  // 反序列化接收到的数据
        console.log(config);
        animation = new Animation(config);
        // 根据config.background设置背景
        if (config.background === 'usbcam') {
        // 检查浏览器是否支持getUserMedia
          if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
            document.body.appendChild(document.createTextNode('浏览器不支持摄像头'));
          } else {
            initCamera(config)
          };
        } else {
          document.body.style.backgroundColor = config.background;
        }
      } 
    );

    window.electron.receiveMessage("newpointer", (data) => {
      const result = JSON.parse(data);  // 反序列化接收到的数据
      const {screen_baggageInfo} = result;
      animation.newpointer();
      if (screen_baggageInfo) {
        animation.creatElement(screen_baggageInfo);
      }
    });
  });
} else {
  document.addEventListener("DOMContentLoaded", () => {
    const config = {
      MonitorHeight: 1080, //屏幕高度，对于LED屏，如西安为64像素高，对于显示屏如深圳，为1080
      MonitorWidth: 1920, //单块屏幕宽度，以西安为例，LED屏不能充分利用整个屏幕，而是在1536处换行；对于显示器，填写实际宽度，如深圳为1920
      background: "black", //usbcam/black/....
      direction: "right-left", // right-left
      layerHeight: 480, //行李标签显示的高度，单位为像素
      presetstep: 3, // 预设速度，每帧移动的像素数
      styleDefualt: {
        color: "green"
      },
      captureArea: { // USB相机截取区域
        x: 40,
        y: 20,
        width: 1070,
        height: 700
      },
      camara: {
        width: 1920, // 请求的摄像头分辨率
        height: 1080, // 请求的摄像头分辨率
        fps: 30,
        brightness: 100,
        contrast: 100,
        saturation: 100,
        hue: 0
      },
      threshold: {
        intervalBetweenTwoRead: 1000, // 两次RFID读取之间的最小时间间隔，单位为毫秒
        lablesLifeTimeSecs: 7200, // 行李标签彻底删除的时间，单位为秒
        timeasStillSecs: 10,
        scanningTimeMS: 1000, //认为标签能被读到的时间，单位为毫秒。RFID持续发送读到的标签，超过这个时间没有被读到，认为读不到了
        deltaHeight: 20, // 高度变化阈值
        minWindowLength: 4, //最小行李的鳞片数阈值
        newWindowHeight: 1.5
      },
      screen: [
        {
          start: 110,
          len_pix: 1800
        },
      ],
    };
    animation = new Animation(config);
    if (config.background === 'usbcam') {
      initCamera(config);
    } else {
      document.body.style.backgroundColor = config.background;
    }

    animation.creatElement({5: [{flight: 'CA1234', dest: 'PEK', layer: 0, lpc: `LPC${performance.now()}`}]});
    setInterval(() => {
      animation.newpointer();
    }, 90);
  });
}

/**
 * 计算两个点的距离
 * @param {number} p1
 * @param {number} p2
 * @returns number
 */
function caclDistance(p1, p2) {
  let differenceValues1 = Math.abs(p1 - p2);
  let differenceValues2 = config.totalplates - differenceValues1;
  return Math.min(differenceValues1, differenceValues2);
}

// 初始化摄像头
async function initCamera(config) {
  console.log('开始初始化摄像头...');
  const errorMessageElement = document.getElementById('error-message');
  
  // 创建video元素
  const video = document.createElement('video');
  video.id = 'video';
  video.autoplay = true;
  video.playsinline = true;
  // 设置video样式
  video.style.position = 'fixed';
  video.style.top = '0';
  video.style.left = '0';
  video.style.minWidth = '100%';
  video.style.minHeight = '100%';
  video.style.width = 'auto';
  video.style.height = 'auto';
  video.style.zIndex = '-1'; // 将z-index设为负值，确保视频位于其他元素下方
  video.style.transformOrigin = 'top left';
  
  document.body.insertBefore(video, document.body.firstChild);
  try {
    console.log('正在请求摄像头权限...');
    const stream = await navigator.mediaDevices.getUserMedia({
      video: {
        width: { ideal: config.camara.width  },
        height: { ideal: config.camara.height },
      }
    });
    console.log('成功获取摄像头权限');

    video.srcObject = stream;
    console.log('正在启动视频流...');
    await video.play();
    console.log('视频流启动成功');

    // 设置视频原始分辨率
    const actualWidth = video.videoWidth;
    const actualHeight = video.videoHeight;
    
    if (!actualWidth || !actualHeight) {
      throw new Error('无法获取视频分辨率');
    }

    video.width = actualWidth;
    video.height = actualHeight;

    // 初始化变换
    const scale = {
      x: window.innerWidth / config.captureArea.width,
      y: window.innerHeight / config.captureArea.height
    };;
    video.style.transform = `
        translate(-${config.captureArea.x}px, -${config.captureArea.y}px)
        scale(${scale.x}, ${scale.y})
    `;
  
    // 窗口大小变化时自动更新
    // window.addEventListener('resize', updateVideoTransform);


    // 隐藏错误信息（如果之前显示过）
    errorMessageElement.style.display = 'none';
  } catch (err) {
    console.error('摄像头初始化错误:', err);
    let errorMessage = '摄像头访问失败';
    
    if (err.name === 'NotFoundError') {
      errorMessage = '未检测到摄像头设备';
    } else if (err.name === 'NotAllowedError') {
      errorMessage = '摄像头访问权限被拒绝';
    } else if (err.name === 'ConstraintNotSatisfiedError') {
      errorMessage = '摄像头不支持请求的分辨率';
    }

    showError(errorMessage);
  }
}

function showError(message) {
  const errorMessageElement = document.getElementById('error-message');
  errorMessageElement.textContent = message;
  errorMessageElement.style.display = 'block';
}
function humanizeTime() {
  const date = new Date();
  const hour = date.getHours().toString().padStart(2, "0");
  const minute = date.getMinutes().toString().padStart(2, "0");
  const second = date.getSeconds().toString().padStart(2, "0");
  return `${hour}:${minute}:${second}`; 
}